package czk.concrent.enjoyModelWithNotLock.stamplock;

import java.util.concurrent.locks.StampedLock;

public class BankAccount {
    private double balance;  // 账户余额
    private final StampedLock lock = new StampedLock();  // StampedLock实例

    // 存款操作（写锁）
    public void deposit(double amount) {
        long stamp = lock.writeLock();  // 获取写锁（阻塞直到获取）
        try {
            System.out.println(Thread.currentThread().getName() + " 存款: +" + amount);
            balance += amount;
        } finally {
            lock.unlockWrite(stamp);  // 释放写锁
        }
    }

    // 取款操作（写锁）
    public void withdraw(double amount) {
        long stamp = lock.writeLock();  // 获取写锁
        try {
            if (balance >= amount) {
                System.out.println(Thread.currentThread().getName() + " 取款: -" + amount);
                balance -= amount;
            } else {
                System.out.println(Thread.currentThread().getName() + " 取款失败! 余额不足");
            }
        } finally {
            lock.unlockWrite(stamp);  // 释放写锁
        }
    }

    // 乐观读锁查询余额
    public double getBalanceOptimistic() {
        long stamp = lock.tryOptimisticRead();  // 尝试获取乐观读锁（非阻塞）
        double currentBalance = balance;        // 读取共享数据

        // 验证期间是否有写操作（关键步骤！）
        if (!lock.validate(stamp)) {
            System.out.println(Thread.currentThread().getName() + " 乐观读验证失败，升级为悲观读锁");

            // 升级为悲观读锁
            stamp = lock.readLock();
            try {
                currentBalance = balance;  // 重新读取最新数据
            } finally {
                lock.unlockRead(stamp);    // 释放悲观读锁
            }
        }
        return currentBalance;
    }

    // 悲观读锁查询余额
    public double getBalancePessimistic() {
        long stamp = lock.readLock();  // 获取悲观读锁（阻塞写操作）
        try {
            return balance;
        } finally {
            lock.unlockRead(stamp);    // 释放读锁
        }
    }

    public static void main(String[] args) throws InterruptedException {
        BankAccount account = new BankAccount();
        account.deposit(1000);  // 初始存款1000

        // 创建读线程（使用乐观读）
        Thread reader1 = new Thread(() -> {
            for (int i = 0; i < 5; i++) {
                double balance = account.getBalanceOptimistic();
                System.out.println(Thread.currentThread().getName() + " 读取余额(乐观): " + balance);
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "Reader-Optimistic");

        // 创建读线程（使用悲观读）
        Thread reader2 = new Thread(() -> {
            for (int i = 0; i < 3; i++) {
                double balance = account.getBalancePessimistic();
                System.out.println(Thread.currentThread().getName() + " 读取余额(悲观): " + balance);
                try {
                    Thread.sleep(150);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "Reader-Pessimistic");

        // 创建写线程（进行存款/取款）
        Thread writer = new Thread(() -> {
            account.deposit(200);
            account.withdraw(50);
            account.deposit(300);
            account.withdraw(100);
        }, "Writer");

        reader1.start();
        reader2.start();
        writer.start();

        reader1.join();
        reader2.join();
        writer.join();

        System.out.println("\n最终余额: " + account.getBalancePessimistic());
    }
}
